
#include "setupdlg.h"
#include "mainwin.h"
#include <qdir.h>
#include <qmessagebox.h>
#include <qsettings.h>
#include <QDate>
#include <QTime>
#include <QDesktopServices>
#include <QFileDialog>
#include <QFontDialog>
#include <QColorDialog>
#include <QKeyEvent>
#include <QDebug>

QMainWin::QMainWin(QWidget* parent)
:QWidget(parent)
{
   QCoreApplication::setOrganizationName("Soup");
   QCoreApplication::setApplicationName("SCFriend");

   this->setupUi(this);


   connect(m_fontPb, SIGNAL(clicked()), this, SLOT(fontBtClick()));
   connect(m_textColorPb, SIGNAL(clicked()), this, SLOT(colorBtClick()));
   connect(m_bgColorPb, SIGNAL(clicked()), this, SLOT(bgColorBtClick()));
   connect(m_connectPb, SIGNAL(clicked()), this, SLOT(connectBtClick()));
   connect(m_clearOutputPb, SIGNAL(clicked()), this, SLOT(clearOutput()));
   connect(m_EnableFilterPb, SIGNAL(clicked()), this, SLOT(EnableNewFilter()));
   connect(m_helpPb, SIGNAL(clicked()), this, SLOT(showHelp()));
   connect(m_aboutPb, SIGNAL(clicked()), this, SLOT(showAboutMsg()));
   connect(m_setupPb, SIGNAL(clicked()), this, SLOT(showSetupDlg()));
   connect(m_quitPb, SIGNAL(clicked()), this, SLOT(close()));

   connect(m_strInputHistoryLw, SIGNAL(itemClicked(QListWidgetItem*)), this, SLOT(oldStrCmdClicked(QListWidgetItem*)));
   connect(m_strInputHistoryLw, SIGNAL(itemDoubleClicked(QListWidgetItem*)), this, SLOT(strInput()));
   connect(m_strInputLw, SIGNAL(returnPressed()), this, SLOT(strInput()));
   connect(m_hexInputHistoryLw, SIGNAL(itemClicked(QListWidgetItem*)), this, SLOT(oldHexCmdClicked(QListWidgetItem*)));
   connect(m_hexInputHistoryLw, SIGNAL(itemDoubleClicked(QListWidgetItem*)), this, SLOT(hexInput()));
   connect(m_hexInputLw, SIGNAL(returnPressed()), this, SLOT(hexInput()));
   connect(m_hexInputLw, SIGNAL(textChanged ( const QString &)), this, SLOT(hexInputTextChanged(const QString &)));

   connect(m_autoInterFileOpenPb, SIGNAL(clicked()), this, SLOT(FindAutoFile()));
   connect(m_startAutoInterPb, SIGNAL(clicked()), this, SLOT(startAuto()));

   connect(&m_serialThread,SIGNAL(AddStr(QString*)),this,SLOT(ReceiveString(QString*)));
 	connect(&m_serialThread,SIGNAL(ShowExeCmd(cmdList *)),this,SLOT(ReceiveExeCmd(cmdList *)));
 
   readSettings();
   m_outputView->document()->setMaximumBlockCount(1000);
   m_FilterOutView->document()->setMaximumBlockCount(500);

   m_isConnected = false;
   m_setupPb->setEnabled(true);
   m_InputTb->setEnabled(false);
   //m_AutoInterPg->setEnabled(false);
   m_connectPb->setFocus();

   //m_cmdLe->installEventFilter(this);
   //m_FilterEnable = false;
   m_filterOutCount = 0;
}

void QMainWin::keyPressEvent( QKeyEvent *event )
{
    //qDebug()<<"key process on main window";
    if((m_isConnected)
        &&(false == event->text().isEmpty()))
    {
        if((0 == m_InputTb->currentIndex())
                &&(false == m_strInputLw->hasFocus()))
        {
            m_strInputLw->setFocus();
            QCoreApplication::sendEvent(m_strInputLw,event);
        }
        else if((1 == m_InputTb->currentIndex())
            && (false == m_hexInputLw->hasFocus()))
        {
            m_hexInputLw->setFocus();
            QCoreApplication::sendEvent(m_hexInputLw,event);
        }
    }
    else if(m_isConnected )
    {
        if(true == m_strInputLw->hasFocus())
        {
             if((event->key() == Qt::Key_Up)
                     ||(event->key() == Qt::Key_Down))
            {
                QString  tmp = m_strInputHistoryLw->currentItem()->text();
                while(tmp.endsWith('\r')|| tmp.endsWith('\n'))
                    tmp.remove(tmp.length()-1, 1);
                if(tmp != m_strInputLw->text())
                {
                    m_strInputLw->setText(tmp);
                }
                else
                {
                    int row = m_strInputHistoryLw->currentRow();
                    if(event->key() == Qt::Key_Up)
                    {
                        if(0 < row)
                            row--;
                        else
                            row = m_strInputHistoryLw->count() - 1;
                    }
                    else
                    {
                        if((m_strInputHistoryLw->count()-1) > row)
                            row++;
                        else
                            row = 0;
                    }
                    m_strInputHistoryLw->setCurrentRow(row);
                    tmp = m_strInputHistoryLw->currentItem()->text();

                    while(tmp.endsWith('\r')|| tmp.endsWith('\n'))
                        tmp.remove(tmp.length()-1, 1);

                    m_strInputLw->setText(tmp);
                }
            }
        }
        else if(true == m_hexInputLw->hasFocus())
        {
            if((event->key() == Qt::Key_Up)
                    ||(event->key() == Qt::Key_Down))
           {
               QString  tmp = m_hexInputHistoryLw->currentItem()->text();
               if(tmp != m_hexInputLw->text())
               {
                   m_hexInputLw->setText(tmp);
               }
               else
               {
                    int row = m_hexInputHistoryLw->currentRow();
                    if((event->key() == Qt::Key_Up))
                    {
                        if(0 < row)
                            row--;
                        else
                            row = m_hexInputHistoryLw->count() - 1;
                    }
                    else
                    {
                        if((m_hexInputHistoryLw->count()-1) > row)
                            row++;
                        else
                            row = 0;
                    }
                    m_hexInputHistoryLw->setCurrentRow(row);
                    m_hexInputLw->setText(
                        m_hexInputHistoryLw->currentItem()->text());
               }
           }
        }
    }
}

void QMainWin::fontBtClick()
{
    bool ok;
    QFont font=QFontDialog::getFont(&ok,m_outputView->font());
    if(ok)
    {
        m_outputView->setFont(font);
        m_FilterOutView->setFont(font);
    }
}

void QMainWin::colorBtClick()
{
    QColor color=QColorDialog::getColor(m_outputView->textColor());
    if(color.isValid())
    {
        m_outputView->setTextColor(color);
        m_FilterOutView->setTextColor(color);
    }
}
void QMainWin::bgColorBtClick()
{
    QPalette pl = m_outputView->palette();
    QColor color=QColorDialog::getColor(pl.base().color());
    if(color.isValid())
    {
        pl.setBrush(QPalette::Base,QBrush(color));
        m_outputView->setPalette(pl);
        m_FilterOutView->setPalette(pl);
    }
}
void QMainWin::FindAutoFile()
{
        QFileDialog  fileDlg ;
        fileDlg.setFileMode(QFileDialog::ExistingFile);
        if(fileDlg.exec() == QDialog::Accepted)
        {
            QStringList strlst = fileDlg.selectedFiles();
            QString str = strlst.at(0);
            m_autoInterLw->setText(str);
        }

}

void QMainWin::startAuto()
{
    if(m_serialThread.m_cmdlist)
    {// stop
	    maintainHistory(m_autoInterHistoryLw, "close current aif file." , true);
        delete (m_serialThread.m_cmdlist);
        m_serialThread.m_cmdlist = NULL;
		m_serialThread.m_curCmd = NULL;
        m_strInputPg->setEnabled(true);
        m_hexInputPg->setEnabled(true);
        m_startAutoInterPb->setText("start");
    }
    else
    { // start
        autointerfile aif;
		
		   int inputMode = m_strInputLineEndCb->currentIndex();
   		switch(inputMode)
   		{
		        case INPUT_LINE_END_LF:
		            aif.m_endFix = '\n';
		            break;
		        case INPUT_LINE_END_CR:
		            aif.m_endFix = '\r';
		            break;
		        case INPUT_LINE_END_LF_CR:
		            aif.m_endFix = '\r' + '\n';
		            break;
		        default:
					aif.m_endFix = "";
		            break;
		   }

        m_serialThread.m_cmdlist = aif.BuildCmdListFromFile(m_autoInterLw->text());
        m_serialThread.m_curCmd = m_serialThread.m_cmdlist->GetFirstExeCmd();
        if(m_serialThread.m_curCmd)
        {
            //m_autoInterHistoryLw->clear();
            maintainHistory(m_autoInterHistoryLw, "start " + m_autoInterLw->text() , true);
            m_serialThread.TrigerCmd(TRIGER_TRY_START, NULL);

            m_strInputPg->setEnabled(false);
            m_hexInputPg->setEnabled(false);
            m_startAutoInterPb->setText("stop");
        }
        else
        {
            maintainHistory(m_autoInterHistoryLw, aif.m_errorinfo, true);
        }
    }
}

 QMainWin::~QMainWin()
{
     saveSettings();
    if (m_serialThread.isRunning())
    {
           m_serialThread.stopp_b = true;
           m_serialThread.wait(1000);
    }
    if(m_serialThread.isRunning())
    {
        m_serialThread.terminate();
        m_serialThread.wait(1000);
    }
}

void QMainWin::saveSettings()
{
   QSettings settings;

   settings.setValue("/uisetting/FontFamily", m_outputView->font().family());
   settings.setValue("/uisetting/FontSize", m_outputView->font().pointSize());
   settings.setValue("/uisetting/FontWeight", m_outputView->font().weight());
   settings.setValue("/uisetting/FontItalic", m_outputView->font().bold());
   settings.setValue("/uisetting/TextColor", m_outputView->textColor().name());
   settings.setValue("/uisetting/BackgroundColor", m_outputView->palette().base().color().name());
   settings.setValue("/uisetting/Width", width());
   settings.setValue("/uisetting/Height", height());
   settings.setValue("/uisetting/Position", pos());

   int historyCount=m_strInputHistoryLw->count();
   if (historyCount>IN_PUT_HISTORY_MAX)
   {
      historyCount=IN_PUT_HISTORY_MAX;
   }
   QStringList saveHist;
   for ( int i=m_strInputHistoryLw->count()-historyCount;i>=0 && i<m_strInputHistoryLw->count(); i++)
   {
      saveHist << m_strInputHistoryLw->item(i)->text();
   }
   settings.setValue("/uisetting/StrInHistory", saveHist);

   saveHist.clear();
   historyCount=m_hexInputHistoryLw->count();
   if (historyCount>IN_PUT_HISTORY_MAX)
   {
      historyCount=IN_PUT_HISTORY_MAX;
   }
   for ( int i=m_hexInputHistoryLw->count()-historyCount;i>=0 && i<m_hexInputHistoryLw->count(); i++)
   {
      saveHist << m_hexInputHistoryLw->item(i)->text();
   }
   settings.setValue("/uisetting/HexInHistory", saveHist);

   m_FilterStringList = m_FilterTxt->text().trimmed().split(";");
   settings.setValue("/uisetting/FilterStringList", m_FilterStringList);
   settings.setValue("/uisetting/FilterEnabled", m_FilterEnable);
   settings.setValue("/uisetting/StrInputLineEnd" , m_strInputLineEndCb->currentIndex());
}

void QMainWin::readSettings()
{
   QSettings settings;

   //m_logFilePathStr = settings.value("/uisetting/LogFileName", QDir::homePath()+"/uisetting.log").toString();

   QString fontFamily = settings.value("/uisetting/FontFamily", NULL).toString();
   int pointSize = settings.value("/uisetting/FontSize", 0).toInt();
   int weight = settings.value("/uisetting/FontWeight",0).toInt();
   bool italic = settings.value("/uisetting/FontItalic",0).toBool();
   if((! fontFamily.isEmpty())&& pointSize && weight)
   {
       QFont font = QFont(fontFamily,pointSize,weight,italic  );
       m_outputView->setFont(font);
	 m_FilterOutView->setFont(font);
   }
   QColor txtColor = (QColor)(settings.value("/uisetting/TextColor", m_outputView->textColor()).toString());
   m_outputView->setTextColor(txtColor);
   m_FilterOutView->setTextColor(txtColor);

   QColor bgColor = (QColor)(settings.value("/uisetting/BackgroundColor",
                                            m_outputView->palette().base().color()).toString());
   QPalette pl = m_outputView->palette();
   pl.setBrush(QPalette::Base,QBrush(bgColor));
   m_outputView->setPalette(pl);
   m_FilterOutView->setPalette(pl);

   int x=settings.value("/uisetting/Width", -1).toInt();
   int y=settings.value("/uisetting/Height", -1).toInt();
   if ((x>100) && (y>100))
   {
      resize(x,y);
   }
   QPoint pt = settings.value("/uisetting/Position", NULL).toPoint();
   move(pt);

   QStringList history=settings.value("/uisetting/StrInHistory").toStringList();
   if (!history.empty())
   {
      m_strInputHistoryLw->addItems(history);
      //m_strInputHistoryLw->scrollToBottom();
      m_strInputHistoryLw->setCurrentRow(
                  m_strInputHistoryLw->count()-1);
   }
   history=settings.value("/uisetting/HexInHistory").toStringList();
   if (!history.empty())
   {
         m_hexInputHistoryLw->addItems(history);
         //m_hexInputHistoryLw->scrollToBottom();
         m_hexInputHistoryLw->setCurrentRow(
                     m_hexInputHistoryLw->count()-1);
   }

   m_FilterStringList =  settings.value("/uisetting/FilterStringList","" ).toStringList();
   m_FilterTxt->setText(m_FilterStringList.join(";"));
   m_FilterEnable = settings.value("/uisetting/FilterEnabled",false).toBool();
   if(false == m_FilterEnable)
   {
           m_FilterTxt->setEnabled(true);
           m_EnableFilterPb->setText("EnableFilter");
   }
   else
   {
           m_FilterTxt->setEnabled(false);
           m_EnableFilterPb->setText("DisableFilter");
   }
   m_strInputLineEndCb->setCurrentIndex(settings.value("/uisetting/StrInputLineEnd", 0).toInt());

}

void QMainWin::showAboutMsg()
{
    QString About;
    About = NAME_AND_VERSION;
    About += "<br>(c)2011-- Soup(Tang Weimin), &lt;soupweimin@yahoo.com.cn&gt;<br>" ;
    About += __DATE__  ;
    About += "                       ";
    About += __TIME__ ;
    About.append("<br>Licensed under the GNU GPL");
    About += "<br>project home page: http://code.google.com/p/scfriend/";
   QMessageBox::about(this, tr("About comfriend"),About);
}

void QMainWin::showHelp()
{

    QUrl url("http://code.google.com/p/scfriend/w/list");
    QDesktopServices::openUrl(url);
}


void QMainWin::showSetupDlg()
{
    SetUpDlg sud(this);
    sud.exec();

    m_outputView->append("\n");
}

void QMainWin::oldHexCmdClicked(QListWidgetItem* item)
{
   if (item==0)
   {
      return;
   }
   m_hexInputLw->setText(item->text());
   m_hexInputLw->setFocus();
}

void QMainWin::oldStrCmdClicked(QListWidgetItem* item)
{
   if (item==0)
   {
      return;
   }
   QString  tmp = item->text();

   while(tmp.endsWith('\r')|| tmp.endsWith('\n'))
       tmp.remove(tmp.length()-1, 1);

   m_strInputLw->setText(tmp);
   m_strInputLw->setFocus();
}

bool QMainWin::maintainHistory(QListWidget * pLw ,QString cmd , bool AllowDup)
{
     if(false == cmd.isEmpty())
    {
        QListWidgetItem *item;
	if(AllowDup == false)
	{
	         for(int i= 0 ; i < pLw->count(); i++)
	         {
	                 if(pLw->item(i)->text() == cmd)
	                 {
                             item = pLw->takeItem(i);
                             delete item;
	                 }
	         }
	}

        pLw->addItem(cmd);
        if (pLw->count()>IN_PUT_HISTORY_MAX)
        {
            item = pLw->takeItem(0);
            delete item;
        }
        pLw->setCurrentRow(pLw->count()-1);
        return true;
    }
     return false;
}
void QMainWin::hexInput()
{
   QString cmd=m_hexInputLw->text().trimmed();
   QString tmp;
   m_hexInputLw->clear();

    if(false == cmd.isEmpty())
   {
        maintainHistory(m_hexInputHistoryLw,cmd);
        tmp = "\n**************** send hex data: \n";
        tmp += cmd;
        if(m_serialThread.writeDataAsynchro(cmd , true))
        {
            tmp += " \n**************** \n";
        }
        else
        {
            tmp += " \n failed, please retry later.\n**************** \n";
        }
        m_outputView->append(tmp);
        //m_outputView->update();
   }

}

void QMainWin::strInput()
{
   QString cmd=m_strInputLw->text().trimmed();
   QString tmp;
   int inputMode = m_strInputLineEndCb->currentIndex();
   m_strInputLw->clear();
   switch(inputMode)
   {
        case INPUT_LINE_END_LF:
            cmd += '\n';
            break;
        case INPUT_LINE_END_CR:
            cmd += '\r';
            break;
        case INPUT_LINE_END_LF_CR:
            cmd += '\r' + '\n';
            break;
        default:
            break;
   }

    if(false == cmd.isEmpty())
   {
        maintainHistory(m_strInputHistoryLw,cmd);
        tmp = "\n**************** send str data: \n";
        tmp += cmd;
        if(m_serialThread.writeDataAsynchro(cmd , false))
        {
            tmp += " \n**************** \n";
        }
        else
        {
            tmp += " \n failed, please retry later.\n**************** \n";
        }
        m_outputView->append(tmp);
        m_outputView->update();
   }
   
}
void QMainWin::connectBtClick()
{
	if(m_isConnected)
	{
            disconnect();
            m_connectPb->setText("Open");
            m_isConnected = false;
	}
	else
	{
            if(doconnect())
            {
                m_autoInterLw->setText("D:\\QtProject\\test.aif");

                m_connectPb->setText( "Close");
                m_isConnected = true;
            }
	}
}

bool QMainWin::doconnect()
{
   m_serialThread.read_b = true;
   m_serialThread.stopp_b = false;
   m_serialThread.start();

   m_serialThread.wait(100);
   if (!m_serialThread.isRunning())
   {
      QMessageBox::information(this, tr("Error"),
                tr("Could not open %1").arg(m_serialThread.m_name));
      return false;
   }
   if (! m_serialThread.m_errorinfo.isEmpty())
   {
       QMessageBox::information(this, tr("Error"), m_serialThread.m_errorinfo);
   }

   m_setupPb->setEnabled(false);
   if(m_serialThread.m_writeAble)
   {
       m_InputTb->setEnabled(true);
        //m_oldCmdsLb->setEnabled(true);
        //m_cmdLe->setEnabled(true);
   }
   QString str = "\n                **************** (" + QDate::currentDate().toString()
           + QTime::currentTime().toString() +")" +
           " Open port " + m_serialThread.m_name + " ****************    \n";
   m_outputView->append(str);
   return true;
}

bool QMainWin::disconnect()
{
	if(m_serialThread.m_cmdlist)
		startAuto();//stop it
	
   m_serialThread.stopp_b  = true;
   m_serialThread.wait(1000);
   //m_outputCurLine = "";
   m_setupPb->setEnabled(true);
   m_InputTb->setEnabled(false);
   //m_oldCmdsLb->setEnabled(false);
   //m_cmdLe->setEnabled(false);
   m_connectPb->setFocus();
   
   QString str = "\n                **************** (" + QDate::currentDate().toString()
           + QTime::currentTime().toString() +")" +
           " Close port " + m_serialThread.m_name + " ****************    \n";
   m_outputView->append(str);
   return true;
}

void QMainWin::ReceiveString(QString * str)
{
   if(NULL == str)
       return;

   if(false == m_serialThread.stopp_b)
   {
       m_outputView->append(*str);

       UpdateFilterView(*str);
   }
   delete str;
}

void QMainWin::ReceiveExeCmd(cmdList * cmd)
{
	if(cmd == NULL)
	{
		    maintainHistory(m_autoInterHistoryLw, "current file finished.", true);
		return ;
	}
	maintainHistory(m_autoInterHistoryLw, cmd->SourceString, true);

	QString tmp;
	if(cmd->node.type == AUTO_INTER_CMD)
	{
		if(cmd->node.data.CmdData.type == WRITE_STR)
		{
			tmp = "\n**************** send str data: \n";
        		tmp += cmd->node.data.CmdData.param.str;
        		tmp += " \n**************** \n";
		        m_outputView->append(tmp);
		}
		if(cmd->node.data.CmdData.type == WRITE_HEX)
		{
			tmp = "\n**************** send hex data: \n";
        		tmp += cmd->node.data.CmdData.param.str;
        		tmp += " \n**************** \n";
		        m_outputView->append(tmp);
		}
		if(cmd->node.data.CmdData.type == WRITE_FILE)
		{
			tmp = "\n**************** send file: \n";
        		tmp += cmd->node.data.CmdData.param.str;
        		tmp += " \n**************** \n";
		        m_outputView->append(tmp);
		}
	}
}

void QMainWin::UpdateFilterView(QString str)
{
        static QString curLine;
        static bool found ;
	if(false == m_FilterEnable) 
	{
           return;
	}

        while(false == str.isEmpty())
	{
                if(-1 == str.indexOf("\n") )
   		{
                    curLine = str;
                    str.clear();
   		}
	   	else
   		{
                    curLine = str.left(str.indexOf("\n") ) ;
                    str.remove(0, str.indexOf("\n") +1);
                }
                found = false;
                for(int i = 0 ; (found == false) && (i < m_FilterStringList.size()); i ++)
                   if(-1 != curLine.indexOf(m_FilterStringList.at(i).trimmed()))
                   {
                          m_FilterOutView->append(curLine);
                          found = true;
                          m_filterOutCount++;
                          curLine.sprintf("Filter output (%d)" ,m_filterOutCount );
                          m_outputTw->setTabText(1,curLine);
                   }
	}   
}

void QMainWin::clearOutput()
{
   QString tmp;
   m_outputView->clear();
   m_FilterOutView->clear();
   m_serialThread.m_hexBytes  = 0;
   m_filterOutCount = 0;
   tmp.sprintf("Filter output (%d)" ,m_filterOutCount );
   m_outputTw->setTabText(1,tmp);
}

void QMainWin::EnableNewFilter()
{
	if(m_FilterEnable)
	{/*	disable it */
		m_FilterEnable = false;
		m_FilterTxt->setEnabled(true);
                m_EnableFilterPb->setText("EnableFilter");
	}
	else
	{/*	enable it 	*/
		m_FilterEnable = true;
		m_FilterTxt->setEnabled(false);
                m_EnableFilterPb->setText("DisableFilter");

                m_FilterStringList=m_FilterTxt->text().trimmed().split(";");
                for(int i = m_FilterStringList.size()-1 ; i >= 0; i--)
                {
                    if(m_FilterStringList.at(i).trimmed().isEmpty())
                        m_FilterStringList.removeAt(i);
                }
                if(m_FilterStringList.size() == 0)
                {
                    QMessageBox::information(this, tr("Can't enable it"),"For no valid filter.");
                    EnableNewFilter();//disable it again.
                }
	}

}


void QMainWin::hexInputTextChanged(const QString & text)
{

        QString tmp = text;
        tmp = tmp.toLower();
        for(int i = tmp.size()-1 ; i >= 0 ; i --)
            if((tmp.at(i)<'0') || (tmp.at(i)>'9' && (tmp.at(i) < 'a')) ||
                    (tmp.at(i) > 'f'))
                tmp.remove(i,1);
        m_hexInputLw->setText(tmp);
}

